<template>
  <view class="tz-autocomplete">
    <tz-search
      id="tz-autocomplete-input"
      v-bind="$attrs"
      @input="handleInput"
      @clear="handleClear"
      @search="handleSearch"
    ></tz-search>
    <popover v-model="state.show" :offset="state.offset">
      <view class="tz-autocomplete-list">
        <view
          v-for="(item, index) in state.options"
          :key="index"
          class="tz-autocomplete-item"
          @click="handleItemClick(item)"
        >
          <tz-icon class="prefix-icon" name="search"></tz-icon>
          <view v-html="item.richLabel"></view>
        </view>
        <tz-text v-show="!state.options.length" class="empty-placeholder">
          没有匹配的数据
        </tz-text>
      </view>
    </popover>
  </view>
</template>
<script>
import { onMounted, onUnmounted, reactive, ref } from "vue";
import Popover from "./Popover.vue";
import TzSearch from "../TzSearch";
import Taro, { eventCenter, getCurrentInstance } from "@tarojs/taro";
import { debounce } from "@/utils/lodash";
export default {
  name: "TzAutocomplete",
  components: {
    popover: Popover,
    "tz-search": TzSearch,
  },
  inheritAttrs: false,
  props: {
    options: {
      type: Array,
      default: () => [],
    },
    labelKey: {
      type: String,
      default: "",
    },
    fetchSuggestions: {
      type: Function,
      default: () => [],
    },
  },
  emits: ["search", "clear", "update:modelValue"],
  setup(props, { emit }) {
    const state = reactive({
      show: false,
      offset: 0,
      options: props.options,
    });
    const inst = Taro.getCurrentInstance();

    onMounted(() => {
      eventCenter.once(inst.router.onReady, () => {
        // onReady 触发后才能获取小程序渲染层的节点
        Taro.createSelectorQuery()
          .select("#tz-autocomplete-input")
          .boundingClientRect()
          .exec((res) => {
            state.offset = res?.[0].height;
          });
      });
    });

    onUnmounted(() => {
      eventCenter.off(inst.router.onReady);
    });

    //防抖处理查询结果
    const fetchSuggestions = debounce((value) => {
      if (!value) return (state.options = []);

      props.fetchSuggestions(value, (options) => {
        state.options = options.map((item) => {
          const label = item?.[props.labelKey] || item;
          const richLabel = label.replace(
            value,
            "<em class='text-red'>$&</em>"
          );
          return { label, richLabel };
        });
      });
    });

    const handleInput = (e) => {
      const value = e.target.value;
      emit("update:modelValue", value);
      state.show = !!value;
      fetchSuggestions(value);
    };

    //处理搜索
    const handleSearch = (event) => {
      state.show = false;
      emit("search", event);
    };

    const handleClear = () => {
      emit("update:modelValue", "");
      state.show = false;
      emit("clear");
    };

    // 搜索条目点击事件
    const handleItemClick = (item) => {
      state.show = false;
      emit("update:modelValue", item.label);
      emit("search", item);
    };

    return { state, handleInput, handleSearch, handleClear, handleItemClick };
  },
};
</script>

<style lang="scss">
.tz-autocomplete {
  display: flex;
  align-items: center;
  position: relative;
  width: 100%;
  &-list {
    width: 100%;
    min-height: 540px;
    text-align: center;

    .empty-placeholder {
      color: $text-color;
      font-size: 15px;
    }
  }
  &-item {
    @extend %bb1;
    width: calc(100% - 15px);
    padding-left: 15px;
    box-sizing: content-box;
    width: 100%;
    display: flex;
    align-items: center;
    font-size: 16px;
    line-height: 44px;

    &:active {
      background-color: $hover-color;
    }
    .prefix-icon,
    .suffix-icon {
      font-size: inherit;
      margin-right: 3px;
      color: $text-color;
    }
    .text-red {
      color: $danger-color;
    }
  }
}
</style>
